﻿using System;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using Actya.Core.Infrastructure;
using Actya.Core.SiteStructure;
using Actya.Web.Infrastructure;
using Actya.Web.Mvc;
using Actya.Web.Mvc.Helpers;
using Actya.Web.ViewModels.Admin;

namespace Actya.Web.Controllers.CmsAdmin
{
	public class InstallController : Controller
	{
		private ISiteService _siteService;
		private readonly ICmsHost _cmsHost;
		private readonly ICmsContext _cmsContext;

		public InstallController()
		{
		}

		public InstallController(ISiteService siteService, ICmsHost cmsHost, ICmsContext cmsContext)
		{
			_siteService = siteService;
			_cmsHost = cmsHost;
			_cmsContext = cmsContext;
		}

		public ActionResult CreateHost()
		{
			// Don't create a duplicate host.
			if (this._cmsHost != null)
			{
				throw new InvalidOperationException(string.Format("The host {0} is already created.", this._cmsHost.Settings.HostUrl));
			}
		    var createHostViewModel = new CreateHostViewModel();
			if (RouteTable.Routes.ContainsRoutesApartFromCmsAdminRoute()) // More routes than the cmsadmin route, we might need the prefix for pages.
            {
                createHostViewModel.ShowPagesPrefix = true;
            }
			AddMembershipOptionsToViewModel(createHostViewModel);

			return View(createHostViewModel);
		}

		[HttpPost]
		[ValidateAntiForgeryToken]
		public ActionResult CreateHost(CreateHostViewModel createHostViewModel)
		{
			// Don't create a duplicate host.
			if (this._cmsHost != null)
			{
				throw new InvalidOperationException(string.Format("The host {0} is already created.", this._cmsHost.Settings.HostUrl));
			}
			// Some validation. Move elsewhere when we have a validation system in place.
			if (createHostViewModel.LocalOrRemoteDatabase == LocalOrRemote.Local && String.IsNullOrEmpty(createHostViewModel.DataDirectory))
			{
				ModelState.AddModelError("DataDirectory", "When choosing a local data store, the data directory is required.");
			}
			if (createHostViewModel.LocalOrRemoteDatabase == LocalOrRemote.Local && Directory.Exists(Path.Combine(Server.MapPath(CmsHost.CmsDataDir), createHostViewModel.DataDirectory)))
			{
				ModelState.AddModelError("DataDirectory", "The data directory is already in use. When running in embedded mode, it's not possible to share the database.");
			}
			if (createHostViewModel.LocalOrRemoteDatabase == LocalOrRemote.Remote && String.IsNullOrEmpty(createHostViewModel.ConnectionString))
			{
				ModelState.AddModelError("ConnectionString", "When choosing a remote data store, the connection string is required.");
			}
			if (RouteTable.Routes.ContainsRoutesApartFromCmsAdminRoute() && String.IsNullOrEmpty(createHostViewModel.PagesPrefix))
			{
				ModelState.AddModelError("PagesPrefix", "The pages prefix is required when we're embedded in an application with existing routes.");
			}
			if (ModelState.IsValid)
			{
				var cmsHost = CmsHost.GetInstance();
				cmsHost.Settings.HostUrl = UrlUtil.GetHostUrlFromRequest(Request);
				if (!String.IsNullOrEmpty(createHostViewModel.DataDirectory))
				{
					cmsHost.Settings.DataDirectory = string.Format("{0}/{1}", CmsHost.CmsDataDir, createHostViewModel.DataDirectory);
				}
				else
				{
					cmsHost.Settings.ConnectionString = createHostViewModel.ConnectionString;		
					cmsHost.Settings.DatabaseName = createHostViewModel.DatabaseName;
				}
				cmsHost.Settings.PagesPrefix = createHostViewModel.PagesPrefix;
				cmsHost.Settings.MembershipType = createHostViewModel.MembershipType;
				cmsHost.Settings.MembershipProvider = createHostViewModel.MembershipProvider;
				cmsHost.Settings.RoleProvider = createHostViewModel.RoleProvider;
				cmsHost.SaveHostSettingsToFile(Path.Combine(Server.MapPath(CmsHost.CmsDataDir), CmsHost.HostSettingsFileName));
				cmsHost.ApplicationState = ApplicationState.Stopped;

				return RedirectToAction("CreateSite");									
			}
			AddMembershipOptionsToViewModel(createHostViewModel);
			return View(createHostViewModel);
		}

		public ActionResult CreateSite()
		{
			// Redirect to site properties when the site already exists.
			if (_cmsContext.Site != null)
			{
				this.ShowMessage(MessageType.Warning,
				                 string.Format("There is already a site created for {0}.", _cmsHost.Settings.HostUrl), true);
				return RedirectToAction("Index", "Site");
			}

			// Check if there is an existing site. If so, add the host url of the current host.
			if (_siteService.VerifyCurrentSiteForHost(this._cmsHost.Settings.HostUrl))
			{
				this.ShowMessage(MessageType.Warning,
								 string.Format("A site was already found in the database. The host {0} is added to the site.", _cmsHost.Settings.HostUrl), true);
				return RedirectToAction("Index", "Site");
			}

			var viewModel = new CreateSiteViewModel();
			viewModel.AvailableThemes = _cmsHost.GetAvailableThemes().Select(t => t.Name).ToArray();
			return View(viewModel);
		}

		[HttpPost]
		[ValidateAntiForgeryToken]
		public ActionResult CreateSite(CreateSiteViewModel viewModel)
		{
			if (ModelState.IsValid)
			{
				var site = _siteService.CreateSite(_cmsHost.Settings.HostUrl, viewModel.Name, viewModel.Theme, viewModel.AdminUsername,
				                        viewModel.AdminPassword);

				// Sign in with the newly created account
				FormsAuthentication.SetAuthCookie(viewModel.AdminUsername, false);

				// Redirect to home page of newly created site.
				var returnUrl = "~/";
				if (! String.IsNullOrEmpty(_cmsHost.Settings.PagesPrefix))
				{
					returnUrl += VirtualPathUtility.AppendTrailingSlash(_cmsHost.Settings.PagesPrefix);
				}
				returnUrl += site.SitemapNodes.First().Url;
				return Redirect(returnUrl);
			}
			viewModel.AvailableThemes = _cmsHost.GetAvailableThemes().Select(t => t.Name).ToArray();
			return View(viewModel);
		}

		private void AddMembershipOptionsToViewModel(CreateHostViewModel createHostViewModel)
		{
			if (Membership.Providers.Count > 0 && Roles.Enabled && Roles.Providers.Count > 0)
			{
				createHostViewModel.ShowMembershipTypeOptions = true;
				createHostViewModel.AvailableMembershipProviders =
					Membership.Providers.OfType<MembershipProvider>().Select(p => p.Name).ToArray();
				createHostViewModel.AvailableRoleProviders = Roles.Providers.OfType<RoleProvider>().Select(p => p.Name).ToArray();
			}
			else
			{
				createHostViewModel.ShowMembershipTypeOptions = false;
			}
		}
	}
}
